/*****************************************************************************
*    Copyright (C)2004 Ali Corporation. All Rights Reserved.
*
*    File:    This file contains m3327 basic function in LLD.
*
*    Description:    Header file in LLD.
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.	4.14.2005        Sam Chen      Ver 0.1       Create file.
*
*****************************************************************************/
#include <sys_config.h>
#include <retcode.h>
#include <types.h>
#include <osal/osal.h>
#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <hal/hal_gpio.h>
#include <hld/hld_dev.h>
#include <hld/nim/nim_dev.h>
#include <hld/nim/nim.h>
#include <hld/nim/nim_tuner.h>		
#include <bus/i2c/i2c.h>
#include <bus/tsi/tsi.h>
#include "nim_tc90512.h"
#if(SYS_DEM_MODULE==TC90512 )

#define NIM_PRINTF(...) 
#define NIM_TC90512_PRINTF(...)

#define TC90512_DEBUG_FLAG	0
#if(TC90512_DEBUG_FLAG)
	#define NIM_TC90512_PRINTF  libc_printf
#else
	#define NIM_TC90512_PRINTF(...)	
#endif

//#define soc_printf(...)
#define Delay_Number	1
#define WAIT_Number	1
#define SYS_WAIT_MS(x) osal_delay((x*1000*WAIT_Number))//osal_task_sleep(x*WAIT_Number)	//osal_delay((x*1000))

#define abs(x)	(x<0) ? -x : x
#define sign(y)	(y>0) ? 1 : -1

#define TC90512_rule
#define Mode_a


#define	NIM_TC90512_FLAG_ENABLE			 0x00000100	//050513 Tom
#define NIM_TC90512_SCAN_END                        0x00000001
#define NIM_TC90512_CHECKING			0x00000002

ID f_TC90512_tracking_task_id = OSAL_INVALID_ID;

ID  	nim_TC90512_flag = OSAL_INVALID_ID;
struct TC90512_Lock_Info				 *TC90512_CurChannelInfo;
static struct TC90512_Demod_Info   	         TC90512_COFDM_Info; 

INT8 TC90512_autoscan_stop_flag = 0;	//50622-01Angus
ID f_IIC_Sema_ID = OSAL_INVALID_ID;

/**************************************************************************************

****************************************************************************************/
#define SYS_TS_INPUT_INTERFACE   TSI_SPI_1
#define WAIT_TUNER_LOCK 200
#define WAIT_OFDM_LOCK  200
#define WAIT_FEC_LOCK     512

#define Sint32T_MAX 2147483647


static UINT32 TC90512_ber = 0;
static UINT32 TC90512_per = 0;
static UINT32 TC90512_per_tot_cnt = 0;



static char nim_TC90512_name[HLD_MAX_NAME_SIZE] = "NIM_TC90512_0";


static INT32 f_TC90512_read(UINT8 dev_add, UINT8 reg_add, UINT8 *data, UINT8 len)
{
	INT32 err;
	
	osal_semaphore_capture(f_IIC_Sema_ID,TMO_FEVR);
	//osal_interrupt_disable();
	
	data[0] = reg_add;
	err = i2c_gpio_write_read(0, dev_add, data, 1, len);
	if(err!=0)
	{	
		NIM_TC90512_PRINTF("nim_TC90512_read: err = %d ,reg_add=%x!\n", err,reg_add);
		;
	}
//		osal_delay(1000);

	osal_semaphore_release(f_IIC_Sema_ID);
	//osal_interrupt_enable();
	return err;

}

static INT32 f_TC90512_write(UINT8 dev_add, UINT8 reg_add, UINT8 *data, UINT8 len)
{
	UINT8  i, buffer[8];
	INT32 err;

	osal_semaphore_capture(f_IIC_Sema_ID,TMO_FEVR);
	//osal_interrupt_disable();
	if (len > 7)
	{
		osal_semaphore_release(f_IIC_Sema_ID);
		//osal_interrupt_enable();
		return ERR_FAILUE;
	}
	buffer[0] = reg_add;
	for (i = 0; i < len; i++)
	{
	    buffer[i + 1] = data[i];
	}

	err=i2c_gpio_write(0, dev_add, buffer, len + 1);
	if(err!=0)
	{	
		NIM_TC90512_PRINTF("nim_TC90512_write: err = %d !\n", err);
		;
	}
	osal_semaphore_release(f_IIC_Sema_ID);
	//osal_interrupt_enable();
	return  err;
}

void f_TC90512_dump_register(struct nim_device *dev)
{
		UINT8  i=0;
		UINT8 data[5];
		for(i=0;i<=0xff;i++)
		{
			f_TC90512_read(dev->base_addr,i,data,1);
		 	NIM_TC90512_PRINTF("reg=0x%x, data=0x%x\n",i,data[0]);
			 osal_delay(100);
		} 

}

void f_TC90512_PassThrough(struct nim_device *dev,BOOL Open)
{	

//Host MCU->start-0x30-0xfe-0xc4-0x00-0x00-0x8a-0x00-stop->
//TC90512->start-0xc4-0x00-0x00-0x8a-0x00-stop->TUNER 

}

static int sembsl_tc90512_reset( struct nim_device *dev ) 
{ 
    int    res=0;   
    UINT8    bytes[4]={0x40,0x10,0x10,0x10}; 
 
    res|=f_TC90512_write(dev->base_addr, 0x01, bytes,1);   
     return res; 
} 
 


/*****************************************************************************
* INT32  f_TC90512_attach()
* Description: TC90512 initialization
*
* Arguments:
*  none
*
* Return Value: INT32
*****************************************************************************/
INT32 f_TC90512_attach(struct COFDM_TUNER_CONFIG_API *ptrCOFDM_Tuner)	//51117-01Angus
{

	struct nim_device *dev;
	struct nim_TC90512_private * priv_mem;
	UINT32 tuner_id=0;
	

	if ((ptrCOFDM_Tuner == NULL))	
	{
		NIM_PRINTF("Tuner Configuration API structure is NULL!/n");
		return ERR_NO_DEV;
	}

	dev = (struct nim_device *)dev_alloc(nim_TC90512_name, HLD_DEV_TYPE_NIM, sizeof(struct nim_device));
	if (dev == NULL)
	{
		NIM_PRINTF("Error: Alloc nim device error!\n");
		return ERR_NO_MEM;
	}

	/* Alloc structure space of private */
	priv_mem = (struct nim_TC90512_private *)MALLOC(sizeof(struct nim_TC90512_private));	
	if ((void*)priv_mem == NULL)
	{
		dev_free(dev);
		
		NIM_TC90512_PRINTF("Alloc nim device prive memory error!/n");
		return ERR_NO_MEM;
	}
	MEMCPY((void*)&(priv_mem->Tuner_Control), (void*)ptrCOFDM_Tuner, sizeof(struct COFDM_TUNER_CONFIG_API));	
	dev->priv = (void*)priv_mem;

	/* Function point init */
	
	dev->base_addr = SYS_COFDM_TC90512_CHIP_ADRRESS;   //please check here
	dev->init = f_TC90512_attach;
	dev->open = f_TC90512_open;
	dev->stop = f_TC90512_close;	
	dev->do_ioctl = f_TC90512_ioctl;
    dev->do_ioctl_ext = f_TC90512_ioctl_ext;
	dev->get_lock = f_TC90512_get_lock;
	dev->get_freq = f_TC90512_get_freq;
	dev->get_FEC = f_TC90512_get_code_rate;
	dev->get_SNR = f_TC90512_get_SNR;
	//dev->get_BER = f_TC90512_get_BER;
	//dev->get_HIER= f_TC90512_get_hier_mode;
	//dev->get_priority=f_TC90512_priority;

#if(SYS_PROJECT_FE == PROJECT_FE_ISDBT)       
    dev->get_AGC = f_TC90512_get_AGC;
    dev->channel_change = f_TC90512_channel_change;
    dev->disable = NULL;
    dev->get_modulation = f_TC90512_get_modulation;
    dev->get_spectrum_inv = NULL;    
    dev->get_fftmode = f_TC90512_get_fftmode;
    dev->get_guard_interval = f_TC90512_get_GI;
    dev->channel_search = f_TC90512_channel_search;            
    dev->get_freq_offset =  NULL;
#endif   

	f_IIC_Sema_ID=osal_semaphore_create(1);

	/*if((((struct nim_TC90512_private*)dev->priv)->Tuner_Control.tuner_config.cChip)!=Tuner_Chip_QUANTEK )
	{
		ptrCOFDM_Tuner->tuner_config.Tuner_Write=NULL;			
		ptrCOFDM_Tuner->tuner_config.Tuner_Read=NULL;			
	}*/

	/* Add this device to queue */
	if (dev_register(dev) != SUCCESS)
	{
		NIM_PRINTF("Error: Register nim device error!\n");
		FREE(priv_mem);
		dev_free(dev);
		return ERR_NO_DEV;
	}

	if (((struct nim_TC90512_private*)dev->priv)->Tuner_Control.nim_Tuner_Init != NULL)	
	{
		if((((struct nim_TC90512_private*)dev->priv)->Tuner_Control.tuner_config.cChip)==Tuner_Chip_QUANTEK || (((struct nim_TC90512_private*)dev->priv)->Tuner_Control.tuner_config.cChip)==Tuner_Chip_MAXLINEAR)
		{
			f_TC90512_PassThrough(dev,TRUE);
		
			
			//if (((struct nim_TC90512_private*)dev->priv)->Tuner_Control.nim_Tuner_Init(&((struct nim_TC90512_private*)dev->priv)->tuner_id, &(ptrCOFDM_Tuner->tuner_config)) != SUCCESS)
			if (((struct nim_TC90512_private*)dev->priv)->Tuner_Control.nim_Tuner_Init(&tuner_id, &(ptrCOFDM_Tuner->tuner_config)) != SUCCESS)	
			{
				NIM_PRINTF("Error: Init Tuner Failure!\n");
				
				f_TC90512_PassThrough(dev,FALSE);				

				return ERR_NO_DEV;
			}	
		
			f_TC90512_PassThrough(dev,FALSE);
		}
		else
		{
			if (((struct nim_TC90512_private*)dev->priv)->Tuner_Control.nim_Tuner_Init(&tuner_id, &(ptrCOFDM_Tuner->tuner_config)) != SUCCESS)	
			{
				NIM_PRINTF("Error: Init Tuner Failure!\n");
				
				return ERR_NO_DEV;
			}

		}

	}


	return SUCCESS;
}


/*****************************************************************************
* INT32 f_TC90512_open(struct nim_device *dev)
* Description: TC90512 open
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_open(struct nim_device *dev)
{

	UINT8	data = 0,i=0;
	UINT8	tdata ;
	UINT8	lock = 0;
	struct nim_TC90512_private * priv_mem = (struct nim_TC90512_private *)(dev->priv);
	struct COFDM_TUNER_CONFIG_API * config_info = &(priv_mem->Tuner_Control);
	INT32 wStatus=0;
	UINT8 wAdrs=0,wData=0;
	UINT8 iexdev=0;
	UINT8 ilpdev=0;
	UINT8 adciqin=0;
	UINT8 zifmd=0;
	UINT8 dif25m=0;
	UINT8 dif25v=0;
	UINT8 difpll=0;
	UINT8 vlfmd=0;
	UINT8 f_inv=0;	
	UINT16 hkfrq=0;
	UINT16 cpld_dt=0;
	UINT8 lpfsl=0;
	UINT16 affrq=0;
	UINT8 agcref1=0;
	UINT8 agcref2=0;

	
	NIM_PRINTF("f_TC90512_open\n");
	
	nim_TC90512_flag = osal_flag_create(NIM_TC90512_FLAG_ENABLE);//050513 Tom

	if (nim_TC90512_flag==OSAL_INVALID_ID)
		return ERR_FAILUE;
		

	TC90512_CurChannelInfo = (struct TC90512_Lock_Info *)MALLOC(sizeof(struct TC90512_Lock_Info));                                                     
	if (TC90512_CurChannelInfo == NULL)
	{
		NIM_PRINTF("f_TC90512_open MALLOC fail!\n");
		return ERR_FAILUE;
	}
	MEMSET(TC90512_CurChannelInfo, 0, sizeof(struct TC90512_Lock_Info));

	
//init TC90512
	for (i=0; i<IF_44m_25p4_ary_size;i++)
	{
		f_TC90512_write(dev->base_addr,IF_44m_25p4_ary_init[2*i],&IF_44m_25p4_ary_init[2*i+1],1);		
		f_TC90512_read(dev->base_addr,IF_44m_25p4_ary_init[2*i],&tdata,1);		
		NIM_TC90512_PRINTF("reg[%x] = %x\n",IF_44m_25p4_ary_init[2*i],tdata);
	}

        
        osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);
        
						
        return SUCCESS;
}
/*****************************************************************************
* void  f_TC90512_get_chip_id(struct nim_device *dev)
* Description:  get  TC90512chip_id 
*
* Arguments: struct nim_device *dev* 
*
* Return Value: 
*****************************************************************************/

void f_TC90512_get_chip_id(struct nim_device *dev)
{	
	UINT8 data[1];
	//f_TC90512_read(dev->base_addr,REGTC90512_CHIP_ID ,data,1);
	NIM_TC90512_PRINTF("CH_ID=%x\n",data[0]);
}




/*****************************************************************************
* INT32  f_TC90512_hw_init()
* Description: TC90512 initialization (set initial register)
*
* Arguments:
*  none
*
* Return Value: INT32
*****************************************************************************/

void f_TC90512_hw_init(struct nim_device *dev)
{
	UINT8 data[5];
	int ret;
	UINT16 i;
	struct nim_TC90512_private * priv_mem = (struct nim_TC90512_private *)(dev->priv);
	struct COFDM_TUNER_CONFIG_API * config_info = &(priv_mem->Tuner_Control);

	
	
	return;

}

/*****************************************************************************
* INT32 f_TC90512_close(struct nim_device *dev)
* Description: TC90512 close
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_close(struct nim_device *dev)
{	
	 UINT8	data[4]={0x10,0x10,0x10,0x10};                       
	

	f_TC90512_write(dev->base_addr, 0x03,data,1);  

		
 	return SUCCESS;
}


/*****************************************************************************
* INT32 f_TC90512_channel_search(struct nim_device *dev, UINT32 freq);

* Description: TC90512 channel search operation
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 freq : Frequency*  
* Return Value: INT32
*****************************************************************************/
//050803 yuchun  add
static INT32 f_TC90512_channel_search(struct nim_device *dev, UINT32 freq,UINT32 bandwidth, 
	UINT8 guard_interval, UINT8 fft_mode, UINT8 modulation, UINT8 fec, UINT8 usage_type, UINT8 inverse,UINT16 freq_offset,UINT8 priority)
{
	UINT8 	i,data[1];
	INT32	chsearch=ERR_FAILED ,center_freq;	
	INT32 freq_offset_reg;

 	UINT32	Center_NPRO,Search_NPRO,tmp_freq;	
	UINT32 First_Frequency;
	UINT8 num,freq_step;
	UINT8 j=0,k = 0;
	INT32 get_freq_offset;
	INT32 remainder;
	UINT16 temp_Step_Freq;

	osal_flag_clear(nim_TC90512_flag,NIM_TC90512_SCAN_END);	

	chsearch=f_TC90512_channel_change(dev,freq,bandwidth,guard_interval,fft_mode,modulation,fec,usage_type,inverse, priority);
		
	osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);
	return chsearch;

}


/*****************************************************************************
* INT32 f_TC90512_channel_change(struct nim_device *dev, UINT32 freq, UINT32 bandwidth, 
	UINT8 guard_interval, UINT8 fft_mode, UINT8 modulation, UINT8 fec, UINT8 usage_type,UINT8 inverse);

* Description: stv0360 channel change operation
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 freq : Frequency
*  Parameter3: UINT32 bandwidth
*  Parameter4: UINT8  guard_interval
*  Parameter5: UINT8  fft_mode
*  Parameter6: UINT8  modulation
*  Parameter7: UINT8  fec
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_channel_change(struct nim_device *dev, UINT32 freq, UINT32 bandwidth, 
	UINT8 guard_interval, UINT8 fft_mode, UINT8 modulation, UINT8 fec, UINT8 usage_type, UINT8 inverse,UINT8 priority)
{

	UINT8	data[6];	//51117-01Angus
	UINT32	temp;
	UINT8	ret_flag = SCAN_TIMEOUT;// LOCK_OK;
	UINT32 	start_time, temp_time;
	struct nim_TC90512_private *dev_priv;	//51117-01Angus
	UINT8 code_rate,Tuner_Retry=0,Demod_Retry=0,hier=0;
	UINT8 lock=0,i=0;	

	dev_priv = (struct nim_TC90512_private *)dev->priv;

	UINT32 tuner_id = 0;//dev_priv->tuner_id;
	
	
	osal_flag_clear(nim_TC90512_flag, NIM_TC90512_CHECKING);

	NIM_TC90512_PRINTF("freq %d, bandwidth %d\n",freq,bandwidth);

	osal_flag_clear(nim_TC90512_flag,NIM_TC90512_SCAN_END);

	TC90512_CurChannelInfo->Frequency = freq;
	TC90512_CurChannelInfo->ChannelBW = bandwidth;

	dev_priv = dev->priv;			

	/*-------------------------------------------------------------------------*/
	/* (1)Set demod                            */
	/*-------------------------------------------------------------------------*/

	if(bandwidth!=6)
			return ERR_FAILED;
	//data[0]=0x00;
      // f_TC90512_write(dev->base_addr, 0x03, data,1); 

	
	/*-------------------------------------------------------------------------*/
	/* (2)Set Tuner   & Channel Acquisition:                             */
	/*-------------------------------------------------------------------------*/
			
		//f_TC90512_PassThrough(dev,TRUE);
		if(dev_priv->Tuner_Control.nim_Tuner_Control(tuner_id, freq,bandwidth,FAST_TIMECST_AGC,data,_1st_i2c_cmd)!=SUCCESS)	
		{
			NIM_TC90512_PRINTF("WRITE tuner fail\n");			
		}
			
		sembsl_tc90512_reset(dev);

	/*-------------------------------------------------------------------------*/
	/* (3)WAIT TUNER_LOCK	                          */
	/*-------------------------------------------------------------------------*/	
		//start_time = osal_get_tick();
	
			Tuner_Retry=0;
			do
			{
				//if((dev_priv->Tuner_Control.tuner_config.cChip)==Tuner_Chip_INFINEON|| (dev_priv->Tuner_Control.tuner_config.cChip)==Tuner_Chip_MAXLINEAR)
					Tuner_Retry++;
					//f_TC90512_PassThrough(dev,TRUE);
					if(dev_priv->Tuner_Control.nim_Tuner_Status(tuner_id ,&lock)==ERR_FAILUE)
					{				
						NIM_TC90512_PRINTF("read tuner fail\n");
						;
					}
					//f_TC90512_PassThrough(dev,FALSE);
                                        NIM_TC90512_PRINTF("Wait Tuner:lock=%d\n ",lock);
				
					if(lock==1)
				        	break;	
					
					else if(Tuner_Retry>5)
					{
						NIM_TC90512_PRINTF("Tuner_ULock\n");
						osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);
						return ERR_FAILED;
					}
						
			}while(lock==0);
			
	/*-------------------------------------------------------------------------*/
	/* (4)WAIT SYNC_LOCK                         */
	/*-------------------------------------------------------------------------*/

	start_time = osal_get_tick();
	Demod_Retry=0;
	while(1)
	{ 		

		 f_TC90512_read(dev->base_addr,0x96,data,1); 
   				  
		 if(data[0]&0xE0) 			
		{
			ret_flag = LOCK_OK; 
			break;		
		}

		 f_TC90512_read(dev->base_addr,0xB0,data,1); 
   		data[0]&=0x0F; 

		/*Demod_Retry++;		
    		if((Demod_Retry>20) &&(data[0]<8))
		{	
			Demod_Retry=0;
			libc_printf("NO TP\n");
			return ERR_FAILED;
		}*/
		
		temp_time = osal_get_tick();
		if(temp_time >= start_time ?  ( temp_time - start_time >1024) : (start_time - temp_time < 0xFFFFFFFF - 1024))
		{
			ret_flag = SCAN_TIMEOUT;			
			NIM_TC90512_PRINTF("TC90512_SYMBOL_NO_LOCK data[0] =0x%x ,ret=%d \n", data[0],ret_flag);
			osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);
			return ERR_FAILED;
		}
	}


	
	/*-------------------------------------------------------------------------*/
	/* (7)Status update:                            */
	/*-------------------------------------------------------------------------*/

	if (ret_flag == LOCK_OK  || ret_flag == TPS_UNLOCK || ret_flag == FEC_UNLOCK)
	{
		
		TC90512_CurChannelInfo->Frequency = freq;
		TC90512_CurChannelInfo->ChannelBW = (UINT8)bandwidth;	

		f_TC90512_getinfo(dev, &code_rate, &guard_interval, &fft_mode, &modulation,&hier);
		
		//MT352_CurChannelInfo->HPRates = code_rate;
		TC90512_CurChannelInfo->Guard= guard_interval;
		TC90512_CurChannelInfo->Mode= fft_mode;
		TC90512_CurChannelInfo->Modulation= modulation;
		TC90512_CurChannelInfo->FECRates = code_rate;

		TC90512_CurChannelInfo->Hierarchy = hier;
		TC90512_CurChannelInfo->Priority=priority;
		TC90512_CurChannelInfo->lock_status=1;

	
		NIM_TC90512_PRINTF("SUCCESS end_time = %d\n",osal_get_tick()-start_time);
		
		osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);		
		return SUCCESS;
	}
	else
	{
		  TC90512_CurChannelInfo->lock_status=0;
		NIM_TC90512_PRINTF("ERR_FAILED end_time = %d ret=%d\n",osal_get_tick()-start_time,ret_flag);	

		osal_flag_set(nim_TC90512_flag,NIM_TC90512_SCAN_END);
		return ERR_FAILED;
	}
}	




static INT32 f_TC90512_getinfo(struct nim_device *dev, UINT8 *code_rate, UINT8 *guard_interval, UINT8 *fft_mode, UINT8 *modulation,UINT8 *hier)
{  
	UINT8 bytes[8];
	UINT8 mode=0;
	UINT8 guard=0;
	UINT8 fec=0;
	UINT8 constall=0;

   f_TC90512_read(dev->base_addr,0x96,bytes,1);  
	
    if(bytes[0]&0x40)
    {	
       *hier=HIER_A;
	NIM_TC90512_PRINTF("HIER_A\n");
    }
    if(bytes[0]&0x20) 
   {	 
	*hier=HIER_B;
	NIM_TC90512_PRINTF("HIER_B\n");
    } 
         
	f_TC90512_read(dev->base_addr,0xB0,bytes,8);  
	
    mode=(bytes[0]>>6)&0x03;  
    if(mode==0)
		 *fft_mode=MODE_2K;  
    if(mode==1) 
		 *fft_mode=MODE_4K;  
	
    if(mode==2)
		 *fft_mode==MODE_8K;  
	
    guard=(bytes[0]>>4)&0x03;  
    if(guard==0) 
		*guard_interval=GUARD_1_32;  
    if(guard==1) 
		*guard_interval=GUARD_1_16;  
    if(guard==2) 
		*guard_interval=GUARD_1_8;  
    if(guard==3)
		*guard_interval=GUARD_1_4;   
 
    fec=(bytes[5]>>5)&0x07;  
    if(fec==0) 
		*code_rate=FEC_1_2;  
    if(fec==1) 
		*code_rate=FEC_2_3;  
    if(fec==2) 
		*code_rate=FEC_3_4;  
    if(fec==3)
		*code_rate=FEC_5_6;  
       if(fec==4)
		*code_rate=FEC_7_8;  

 
    constall=(bytes[3]>>5)&0x07; 
    if(constall==0) 
		*modulation=CONST_DQPSK;  
    if(constall==1) 
		*modulation=CONST_QPSK;  
    if(constall==2) 
		*modulation=CONST_16QAM;  
    if(constall==3)
		*modulation=CONST_64QAM;  
}

/*****************************************************************************
* INT32 f_TC90512_get_lock(struct nim_device *dev, UINT8 *lock)
*
*  Read FEC lock status
*
*Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: BOOL *fec_lock
*
*Return Value: INT32
*****************************************************************************/

static INT32 f_TC90512_get_lock(struct nim_device *dev, UINT8 *lock)
{
	UINT8 data=0;
	OSAL_ER	result;
       UINT32	flgptn;
	static UINT32 dd_time=0; 
	UINT8 ber_vld;
	UINT32 m_vbber, m_per;	
	
	result = osal_flag_wait(&flgptn,nim_TC90512_flag, NIM_TC90512_SCAN_END, OSAL_TWF_ANDW,0);
	if(OSAL_E_OK!=result)
	{
        	//libc_printf("Get LOCK Fail, Wait ChannelChg Complete!\n");
		*lock=0xff;
	}    
	
	else 
	{	
 		 f_TC90512_read(dev->base_addr,0xB0,&data,1); 
   		data&=0x0F; 
		
    		if(0<data) 
		{		
			NIM_TC90512_PRINTF("FE_HAS_SIGNAL ! \n");
		}
		if(2<data) 
		{		
			NIM_TC90512_PRINTF("FE_HAS_CARRIER ! \n");
		}
		if(8<data) 
		{		
			NIM_TC90512_PRINTF("FE_HAS_SYNC ! \n");
		}

		 f_TC90512_read(dev->base_addr,0x96,&data,1); 
   				  
		 if(data&0xE0) 
		 {
			NIM_TC90512_PRINTF("FE_HAS_VITERBI ! \n");
			*lock=1;
			TC90512_CurChannelInfo->lock_status=1;
		 }
		 else
		 {	
		 	*lock=0;
			TC90512_CurChannelInfo->lock_status=0;
		 }

		  f_TC90512_read(dev->base_addr,0xB2,&data,1); 		   
   		  if(data&0x02)	
		  {	
		  	//libc_printf("EWS start\n");
		  	;
   		  }	
	
	}
	
	return SUCCESS;
}

/*****************************************************************************
* INT32 f_TC90512_get_freq(struct nim_device *dev, UINT32 *freq)
* Read M3327 frequence
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 *freq			:
*
* Return Value: void
*****************************************************************************/
static INT32 f_TC90512_get_freq(struct nim_device *dev, UINT32 *freq)
{
	INT32 freq_off=0;
	UINT8  data[3];
	INT32  tdata=0;
        OSAL_ER	result;
        UINT32	flgptn;       
#if 0
 	result = osal_flag_wait(&flgptn,nim_TC90512_flag, NIM_TC90512_SCAN_END, OSAL_TWF_ANDW,0);//050725 yuchun
	if(OSAL_E_OK!=result)
	{
        	NIM_PRINTF("Get Frequency Fail, Wait ChannelChg Complete!\n");
		*freq=0;
	}    
        
		
#endif	

	*freq=TC90512_CurChannelInfo->Frequency;
       
	return SUCCESS;
	
}

/*****************************************************************************
* INT32 f_TC90512_get_code_rate(struct nim_device *dev, UINT8* code_rate)
* Description: Read TC90512 code rate
*   FEC status (b6-b4)                      code rate                 return value
*	0					1/2			1
*	1					2/3			4
*	2					3/4			8
*	3					5/6			16	
*	5					7/8			32
*		
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* code_rate
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_get_code_rate(struct nim_device *dev, UINT8* code_rate)
{
	*code_rate = TC90512_CurChannelInfo->FECRates;
	return SUCCESS;

}
	
/*****************************************************************************
* INT32 f_TC90512_get_GI(struct nim_device *dev, UINT8 *guard_interval)
* Description: Read TC90512 guard interval
*  Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* guard_interval
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_get_GI(struct nim_device *dev, UINT8 *guard_interval)
{

	*guard_interval = TC90512_CurChannelInfo->Guard;
	return SUCCESS;

}


/*****************************************************************************
* INT32 f_TC90512_get_fftmode(struct nim_device *dev, UINT8 *fft_mode)
* Description: Read TC90512 fft_mode
*  Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* fft_mode
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_get_fftmode(struct nim_device *dev, UINT8 *fft_mode)
{
	*fft_mode = TC90512_CurChannelInfo->Mode;
	return SUCCESS;
}


/*****************************************************************************
* INT32 f_TC90512_get_modulation(struct nim_device *dev, UINT8 *modulation)
* Description: Read TC90512 modulation
*  Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* modulation
*
* Return Value: INT32
*****************************************************************************/

static INT32 f_TC90512_get_modulation(struct nim_device *dev, UINT8 *modulation)
{

	*modulation = TC90512_CurChannelInfo->Modulation;
	return SUCCESS;

}
/*****************************************************************************
* INT32 f_TC90512_get_AGC(struct nim_device *dev, UINT8 *agc)
*
*  This function will access the NIM to determine the AGC feedback value
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* agc
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_get_AGC(struct nim_device *dev, UINT16 *agc)
{
	 UINT8		data[2];
	 UINT16		agc_if=0;	 
	 OSAL_ER	result;
	 UINT32		flgptn;	
 	 UINT16	rssi;
	struct nim_TC90512_private *dev_priv;
	 
	result = osal_flag_wait(&flgptn,nim_TC90512_flag, NIM_TC90512_SCAN_END, OSAL_TWF_ANDW,0);
	//libc_printf("AGC result = %d\r\n",result);
	if(OSAL_E_OK!=result)
	{
        	NIM_PRINTF("Get AGC Fail, Wait ChannelChg Complete!\n");
		*agc = 0;		
	} 
	else
	{ 
		if(TC90512_CurChannelInfo->lock_status==1)
		{		

			  f_TC90512_read(dev->base_addr,0x82,data,2); //0x82 if_agc.0x83 rf_agc
			  //libc_printf("If_agc=%x ,RF agc=%x\n",data[0],data[1]);
			  
			  rssi=(UINT16)(~((data[1]<<8)|data[0])); 

			  //libc_printf("rssi=%d\n",rssi);

			  if(rssi>255)
			  	rssi=255;

			  if(rssi<155)
			  	rssi=155;

			  if(rssi>212)
			  	*agc=100;
			 else if((rssi>195)&&(rssi<=212))
			 	*agc=rssi-120;
			  else if((rssi>184)&&(rssi<=195))
			 	*agc=rssi-130;
			 else if((rssi>176)&&(rssi<=184))
			 	*agc=rssi-155;
			 else
				*agc=20;
			 
			  TC90512_CurChannelInfo->strength= *agc;
			  
			  //libc_printf("AGC=%d\n",*agc);

		}
		else
		{	
			*agc=0;
			  TC90512_CurChannelInfo->strength=0;
		}
	}

	return SUCCESS;



	
}

/*****************************************************************************
* INT32 f_TC90512_get_SNR(struct nim_device *dev, UINT8 *snr)
*
* This function returns an approximate estimation of the SNR from the NIM
* 
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 *snr
*
* Return Value: * snr

*****************************************************************************/
static INT32 f_TC90512_get_SNR(struct nim_device *dev, UINT8 *snr)
{
	UINT8	data;
	OSAL_ER result;
	UINT32 	flgptn;
	UINT32 vbber=0;

		
	result = osal_flag_wait(&flgptn,nim_TC90512_flag, NIM_TC90512_SCAN_END, OSAL_TWF_ANDW,0);
    //libc_printf("SNR result = %d\r\n",result);
	if(OSAL_E_OK!=result)
	{
        	NIM_PRINTF("Get SNR Fail, Wait ChannelChg Complete!\n");
		*snr = 0;		
	}    
	else
	{	
		if(TC90512_CurChannelInfo->lock_status==1)
		{	

			// f_TC90512_get_BER(dev, &vbber);
			
			if(TC90512_CurChannelInfo->strength==100)
			*snr=100;
			else
			*snr=TC90512_CurChannelInfo->strength-2;

			if(*snr>100)
				*snr=100;

			if(*snr<20)
				*snr=20;

			//libc_printf("%d\n",*snr);
		}
		else
			*snr=0;
	}
		return SUCCESS;		
}


/*****************************************************************************
* INT32 f_TC90512_get_BER(struct nim_device *dev, UINT32 *RsUbc)
* Reed Solomon Uncorrected block count
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 f_TC90512_get_BER(struct nim_device *dev, UINT32 *vbber)
{
	UINT32 dwPeriod=0,dwCount=0;
	UINT32 temp,temp1;
	UINT32 ber;
	INT32 i;
	UINT8 bytes[3];
	OSAL_ER result;
	UINT32 	flgptn;


	result = osal_flag_wait(&flgptn,nim_TC90512_flag, NIM_TC90512_SCAN_END, OSAL_TWF_ANDW,0);
	//libc_printf("BER result = %d\r\n",result);
	if(OSAL_E_OK!=result)
	{
        	NIM_PRINTF("Get SNR Fail, Wait ChannelChg Complete!\n");
		*vbber = 0;	
	}    
	else
	{
		 f_TC90512_read(dev->base_addr,0x96,bytes,1); 

		if(bytes[0]&0x02) //b_flag
		{ 
		        f_TC90512_read(dev->base_addr,0xA0,bytes,3); 
		      
		        dwCount=(bytes[0]<<16)|(bytes[1]<<8)|(bytes[2]);  
		        dwCount=((100000000/(1024*204*8))*dwCount);
			TC90512_ber=dwCount;
			*vbber=dwCount;
			NIM_TC90512_PRINTF("ber=%d\n",dwCount);
		       // p_obj->state.ber[1]=(BERcount+p_obj->state.ber[1])>>1; 
	    	} 

	
	}
	return SUCCESS;			
}
        
        

		
static INT32 f_TC90512_ioctl(struct nim_device *dev, INT32 cmd, UINT32 param)	//50622-01Angus
{
	static UINT32 rec_ber_cnt = 0;
	nim_rec_performance_t * p_nim_rec_performance;
	INT32 ret_val = ERR_FAILUE;
	
	switch( cmd )
	{
		case NIM_DRIVER_STOP_ATUOSCAN:
			TC90512_autoscan_stop_flag = param;
		    break;		
		case NIM_DRIVER_GET_REC_PERFORMANCE_INFO:
			p_nim_rec_performance = (nim_rec_performance_t *)param;
			f_TC90512_get_lock(dev, &(p_nim_rec_performance->lock));

			if (p_nim_rec_performance->lock == 1)
			{
				if (rec_ber_cnt !=TC90512_per_tot_cnt)
				{
					rec_ber_cnt = TC90512_per_tot_cnt;
					p_nim_rec_performance->ber = TC90512_ber;
					p_nim_rec_performance->per = TC90512_per;
					p_nim_rec_performance->valid = TRUE;
				}
				else
				{
					p_nim_rec_performance->valid = FALSE;					
				}
			}

			ret_val = SUCCESS;
			
			break;	
        case NIM_DRIVER_DISABLED:
            break;
        case NIM_DRIVER_GET_AGC:
            return f_TC90512_get_AGC(dev, (UINT16 *)param);
            break;
        case NIM_DRIVER_GET_BER:
            return f_TC90512_get_BER(dev, (UINT32 *)param);
            break;
        case NIM_DRIVER_GET_GUARD_INTERVAL:
            return f_TC90512_get_GI(dev, (UINT8 *)param);
            break;
        case NIM_DRIVER_GET_FFT_MODE:
            return f_TC90512_get_fftmode(dev, (UINT8 *)param);
            break;
        case NIM_DRIVER_GET_MODULATION:
            return f_TC90512_get_modulation(dev, (UINT8 *)param);
            break;
        case NIM_DRIVER_GET_SPECTRUM_INV:
            break;               	
		default:
		    break;
	}
	return SUCCESS;
}


static INT32 f_TC90512_ioctl_ext(struct nim_device *dev, INT32 cmd, void * param_list)
{
    struct NIM_Channel_Change *change_para;
    struct NIM_Channel_Search *search_para;
	NIM_PRINTF("Enter f_TC90512_ioctl_ext()...\n");
	switch (cmd)
	{
        case NIM_DRIVER_CHANNEL_CHANGE:
            change_para = (struct NIM_Channel_Change *)param_list;
            return f_TC90512_channel_change(dev, change_para->freq, change_para->bandwidth, \
                change_para->guard_interval, change_para->fft_mode, change_para->modulation, \
                change_para->fec, change_para->usage_type, change_para->inverse, change_para->priority);
            break;
        case NIM_DRIVER_CHANNEL_SEARCH:    
            search_para = (struct NIM_Channel_Search *)param_list;
            return f_TC90512_channel_search(dev, search_para->freq, search_para->bandwidth, \
                search_para->guard_interval, search_para->fft_mode, search_para->modulation, \
                search_para->fec, search_para->usage_type, search_para->inverse, \
                search_para->freq_offset, search_para->priority);
            break;
        default:
            break;
	}
	NIM_PRINTF("Exit f_TC90512_ioctl_ext() normally.\n");        
	return SUCCESS;
}

#endif
